# -*- coding: utf-8 -*-

# Copyright (c) 2013 - 2025 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog for entering character classes.
"""

from PyQt6.QtCore import QRegularExpression
from PyQt6.QtGui import QRegularExpressionValidator
from PyQt6.QtWidgets import (
    QComboBox,
    QDialog,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QPushButton,
    QScrollArea,
    QSizePolicy,
    QSpacerItem,
    QVBoxLayout,
    QWidget,
)

from .Ui_QRegularExpressionWizardCharactersDialog import (
    Ui_QRegularExpressionWizardCharactersDialog,
)


class QRegularExpressionWizardCharactersDialog(
    QDialog, Ui_QRegularExpressionWizardCharactersDialog
):
    """
    Class implementing a dialog for entering character classes.
    """

    def __init__(self, parent=None):
        """
        Constructor

        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)

        self.__initCharacterSelectors()

        self.comboItems = []
        self.singleComboItems = []  # these are in addition to the above
        self.comboItems.append((self.tr("Normal character"), "-c"))
        self.comboItems.append(
            (self.tr("Unicode character in hexadecimal notation"), "-h")
        )
        self.comboItems.append(
            (self.tr("ASCII/Latin1 character in octal notation"), "-o")
        )
        self.singleComboItems.extend(
            [
                ("---", "-i"),
                (self.tr("Bell character (\\a)"), "\\a"),
                (self.tr("Escape character (\\e)"), "\\e"),
                (self.tr("Page break (\\f)"), "\\f"),
                (self.tr("Line feed (\\n)"), "\\n"),
                (self.tr("Carriage return (\\r)"), "\\r"),
                (self.tr("Horizontal tabulator (\\t)"), "\\t"),
                ("---", "-i"),
                (self.tr("Character Category"), "-ccp"),
                (self.tr("Special Character Category"), "-csp"),
                (self.tr("Character Block"), "-cbp"),
                (self.tr("POSIX Named Set"), "-psp"),
                (self.tr("Not Character Category"), "-ccn"),
                (self.tr("Not Character Block"), "-cbn"),
                (self.tr("Not Special Character Category"), "-csn"),
                (self.tr("Not POSIX Named Set"), "-psn"),
            ]
        )

        self.charValidator = QRegularExpressionValidator(
            QRegularExpression(".{0,1}"), self
        )
        self.hexValidator = QRegularExpressionValidator(
            QRegularExpression("[0-9a-fA-F]{0,4}"), self
        )
        self.octValidator = QRegularExpressionValidator(
            QRegularExpression("[0-3]?[0-7]{0,2}"), self
        )

        # generate dialog part for single characters
        self.singlesBoxLayout = QVBoxLayout(self.singlesBox)
        self.singlesBoxLayout.setObjectName("singlesBoxLayout")
        self.singlesBoxLayout.setSpacing(6)
        self.singlesBoxLayout.setContentsMargins(6, 6, 6, 6)
        self.singlesBox.setLayout(self.singlesBoxLayout)
        self.singlesView = QScrollArea(self.singlesBox)
        self.singlesView.setObjectName("singlesView")
        self.singlesBoxLayout.addWidget(self.singlesView)

        self.singlesItemsBox = QWidget(self)
        self.singlesView.setWidget(self.singlesItemsBox)
        self.singlesItemsBox.setObjectName("singlesItemsBox")
        self.singlesItemsBox.setMinimumWidth(1000)
        self.singlesItemsBoxLayout = QVBoxLayout(self.singlesItemsBox)
        self.singlesItemsBoxLayout.setContentsMargins(6, 6, 6, 6)
        self.singlesItemsBoxLayout.setSpacing(6)
        self.singlesItemsBox.setLayout(self.singlesItemsBoxLayout)
        self.singlesEntries = []
        self.__addSinglesLine()

        hlayout0 = QHBoxLayout()
        hlayout0.setContentsMargins(0, 0, 0, 0)
        hlayout0.setSpacing(6)
        hlayout0.setObjectName("hlayout0")
        self.moreSinglesButton = QPushButton(
            self.tr("Additional Entries"), self.singlesBox
        )
        self.moreSinglesButton.setObjectName("moreSinglesButton")
        hlayout0.addWidget(self.moreSinglesButton)
        hspacer0 = QSpacerItem(
            30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum
        )
        hlayout0.addItem(hspacer0)
        self.singlesBoxLayout.addLayout(hlayout0)
        self.moreSinglesButton.clicked.connect(self.__addSinglesLine)

        # generate dialog part for character ranges
        self.rangesBoxLayout = QVBoxLayout(self.rangesBox)
        self.rangesBoxLayout.setObjectName("rangesBoxLayout")
        self.rangesBoxLayout.setSpacing(6)
        self.rangesBoxLayout.setContentsMargins(6, 6, 6, 6)
        self.rangesBox.setLayout(self.rangesBoxLayout)
        self.rangesView = QScrollArea(self.rangesBox)
        self.rangesView.setObjectName("rangesView")
        self.rangesBoxLayout.addWidget(self.rangesView)

        self.rangesItemsBox = QWidget(self)
        self.rangesView.setWidget(self.rangesItemsBox)
        self.rangesItemsBox.setObjectName("rangesItemsBox")
        self.rangesItemsBox.setMinimumWidth(1000)
        self.rangesItemsBoxLayout = QVBoxLayout(self.rangesItemsBox)
        self.rangesItemsBoxLayout.setContentsMargins(6, 6, 6, 6)
        self.rangesItemsBoxLayout.setSpacing(6)
        self.rangesItemsBox.setLayout(self.rangesItemsBoxLayout)
        self.rangesEntries = []
        self.__addRangesLine()

        hlayout1 = QHBoxLayout()
        hlayout1.setContentsMargins(0, 0, 0, 0)
        hlayout1.setSpacing(6)
        hlayout1.setObjectName("hlayout1")
        self.moreRangesButton = QPushButton(
            self.tr("Additional Entries"), self.rangesBox
        )
        self.moreSinglesButton.setObjectName("moreRangesButton")
        hlayout1.addWidget(self.moreRangesButton)
        hspacer1 = QSpacerItem(
            30, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum
        )
        hlayout1.addItem(hspacer1)
        self.rangesBoxLayout.addLayout(hlayout1)
        self.moreRangesButton.clicked.connect(self.__addRangesLine)

    def __initCharacterSelectors(self):
        """
        Private method to initialize the W3C character selector entries.
        """
        self.__characterCategories = (
            # display name                                  code
            (self.tr("Letter, Any"), "L"),
            (self.tr("Letter, Lower case"), "Ll"),
            (self.tr("Letter, Modifier"), "Lm"),
            (self.tr("Letter, Other"), "Lo"),
            (self.tr("Letter, Title case"), "Lt"),
            (self.tr("Letter, Upper case"), "Lu"),
            (self.tr("Letter, Lower, Upper or Title"), "L&"),
            (self.tr("Mark, Any"), "M"),
            (self.tr("Mark, Spacing"), "Mc"),
            (self.tr("Mark, Enclosing"), "Me"),
            (self.tr("Mark, Non-spacing"), "Mn"),
            (self.tr("Number, Any"), "N"),
            (self.tr("Number, Decimal"), "Nd"),
            (self.tr("Number, Letter"), "Nl"),
            (self.tr("Number, Other"), "No"),
            (self.tr("Punctuation, Any"), "P"),
            (self.tr("Punctuation, Connector"), "Pc"),
            (self.tr("Punctuation, Dash"), "Pd"),
            (self.tr("Punctuation, Close"), "Pe"),
            (self.tr("Punctuation, Final"), "Pf"),
            (self.tr("Punctuation, Initial"), "Pi"),
            (self.tr("Punctuation, Other"), "Po"),
            (self.tr("Punctuation, Open"), "Ps"),
            (self.tr("Symbol, Any"), "S"),
            (self.tr("Symbol, Currency"), "Sc"),
            (self.tr("Symbol, Modifier"), "Sk"),
            (self.tr("Symbol, Mathematical"), "Sm"),
            (self.tr("Symbol, Other"), "So"),
            (self.tr("Separator, Any"), "Z"),
            (self.tr("Separator, Line"), "Zl"),
            (self.tr("Separator, Paragraph"), "Zp"),
            (self.tr("Separator, Space"), "Zs"),
            (self.tr("Other, Any"), "C"),
            (self.tr("Other, Control"), "Cc"),
            (self.tr("Other, Format"), "Cf"),
            (self.tr("Other, Unassigned"), "Cn"),
            (self.tr("Other, Private Use"), "Co"),
            (self.tr("Other, Surrogat"), "Cn"),
        )

        self.__specialCharacterCategories = (
            # display name                           code
            (self.tr("Alphanumeric"), "Xan"),
            (self.tr("POSIX Space"), "Xps"),
            (self.tr("Perl Space"), "Xsp"),
            (self.tr("Universal Character"), "Xuc"),
            (self.tr("Perl Word"), "Xan"),
        )

        self.__characterBlocks = (
            # display name                           code
            (self.tr("Arabic"), "Arabic"),
            (self.tr("Armenian"), "Armenian"),
            (self.tr("Avestan"), "Avestan"),
            (self.tr("Balinese"), "Balinese"),
            (self.tr("Bamum"), "Bamum"),
            (self.tr("Batak"), "Batak"),
            (self.tr("Bengali"), "Bengali"),
            (self.tr("Bopomofo"), "Bopomofo"),
            (self.tr("Brahmi"), "Brahmi"),
            (self.tr("Braille"), "Braille"),
            (self.tr("Buginese"), "Buginese"),
            (self.tr("Buhid"), "Buhid"),
            (self.tr("Canadian Aboriginal"), "Canadian_Aboriginal"),
            (self.tr("Carian"), "Carian"),
            (self.tr("Chakma"), "Chakma"),
            (self.tr("Cham"), "Cham"),
            (self.tr("Cherokee"), "Cherokee"),
            (self.tr("Common"), "Common"),
            (self.tr("Coptic"), "Coptic"),
            (self.tr("Cuneiform"), "Cuneiform"),
            (self.tr("Cypriot"), "Cypriot"),
            (self.tr("Cyrillic"), "Cyrillic"),
            (self.tr("Deseret"), "Deseret,"),
            (self.tr("Devanagari"), "Devanagari"),
            (self.tr("Egyptian Hieroglyphs"), "Egyptian_Hieroglyphs"),
            (self.tr("Ethiopic"), "Ethiopic"),
            (self.tr("Georgian"), "Georgian"),
            (self.tr("Glagolitic"), "Glagolitic"),
            (self.tr("Gothic"), "Gothic"),
            (self.tr("Greek"), "Greek"),
            (self.tr("Gujarati"), "Gujarati"),
            (self.tr("Gurmukhi"), "Gurmukhi"),
            (self.tr("Han"), "Han"),
            (self.tr("Hangul"), "Hangul"),
            (self.tr("Hanunoo"), "Hanunoo"),
            (self.tr("Hebrew"), "Hebrew"),
            (self.tr("Hiragana"), "Hiragana"),
            (self.tr("Imperial Aramaic"), "Imperial_Aramaic"),
            (self.tr("Inherited"), "Inherited"),
            (self.tr("Inscriptional Pahlavi"), "Inscriptional_Pahlavi"),
            (self.tr("Inscriptional Parthian"), "Inscriptional_Parthian"),
            (self.tr("Javanese"), "Javanese"),
            (self.tr("Kaithi"), "Kaithi"),
            (self.tr("Kannada"), "Kannada"),
            (self.tr("Katakana"), "Katakana"),
            (self.tr("Kayah Li"), "Kayah_Li"),
            (self.tr("Kharoshthi"), "Kharoshthi"),
            (self.tr("Khmer"), "Khmer"),
            (self.tr("Lao"), "Lao"),
            (self.tr("Latin"), "Latin"),
            (self.tr("Lepcha"), "Lepcha"),
            (self.tr("Limbu"), "Limbu"),
            (self.tr("Linear B"), "Linear_B"),
            (self.tr("Lisu"), "Lisu"),
            (self.tr("Lycian"), "Lycian"),
            (self.tr("Lydian"), "Lydian"),
            (self.tr("Malayalam"), "Malayalam"),
            (self.tr("Mandaic"), "Mandaic"),
            (self.tr("Meetei Mayek"), "Meetei_Mayek"),
            (self.tr("Meroitic Cursive"), "Meroitic_Cursive"),
            (self.tr("Meroitic Hieroglyphs"), "Meroitic_Hieroglyphs"),
            (self.tr("Miao"), "Miao"),
            (self.tr("Mongolian"), "Mongolian"),
            (self.tr("Myanmar"), "Myanmar"),
            (self.tr("New Tai Lue"), "New_Tai_Lue"),
            (self.tr("N'Ko"), "Nko"),
            (self.tr("Ogham"), "Ogham"),
            (self.tr("Old Italic"), "Old_Italic"),
            (self.tr("Old Persian"), "Old_Persian"),
            (self.tr("Old South Arabian"), "Old_South_Arabian"),
            (self.tr("Old Turkic"), "Old_Turkic,"),
            (self.tr("Ol Chiki"), "Ol_Chiki"),
            (self.tr("Oriya"), "Oriya"),
            (self.tr("Osmanya"), "Osmanya"),
            (self.tr("Phags-pa"), "Phags_Pa"),
            (self.tr("Phoenician"), "Phoenician"),
            (self.tr("Rejang"), "Rejang"),
            (self.tr("Runic"), "Runic"),
            (self.tr("Samaritan"), "Samaritan"),
            (self.tr("Saurashtra"), "Saurashtra"),
            (self.tr("Sharada"), "Sharada"),
            (self.tr("Shavian"), "Shavian"),
            (self.tr("Sinhala"), "Sinhala"),
            (self.tr("Sora Sompeng"), "Sora_Sompeng"),
            (self.tr("Sundanese"), "Sundanese"),
            (self.tr("Syloti Nagri"), "Syloti_Nagri"),
            (self.tr("Syriac"), "Syriac"),
            (self.tr("Tagalog"), "Tagalog"),
            (self.tr("Tagbanwa"), "Tagbanwa"),
            (self.tr("Tai Le"), "Tai_Le"),
            (self.tr("Tai Tham"), "Tai_Tham"),
            (self.tr("Tai Viet"), "Tai_Viet"),
            (self.tr("Takri"), "Takri"),
            (self.tr("Tamil"), "Tamil"),
            (self.tr("Telugu"), "Telugu"),
            (self.tr("Thaana"), "Thaana"),
            (self.tr("Thai"), "Thai"),
            (self.tr("Tibetan"), "Tibetan"),
            (self.tr("Tifinagh"), "Tifinagh"),
            (self.tr("Ugaritic"), "Ugaritic"),
            (self.tr("Vai"), "Vai"),
            (self.tr("Yi"), "Yi"),
        )

        self.__posixNamedSets = (
            # display name                                  code
            (self.tr("Alphanumeric"), "alnum"),
            (self.tr("Alphabetic"), "alpha"),
            (self.tr("ASCII"), "ascii"),
            (self.tr("Word Letter"), "word"),
            (self.tr("Lower Case Letter"), "lower"),
            (self.tr("Upper Case Letter"), "upper"),
            (self.tr("Decimal Digit"), "digit"),
            (self.tr("Hexadecimal Digit"), "xdigit"),
            (self.tr("Space or Tab"), "blank"),
            (self.tr("White Space"), "space"),
            (self.tr("Printing (excl. space)"), "graph"),
            (self.tr("Printing (incl. space)"), "print"),
            (self.tr("Printing (excl. alphanumeric)"), "punct"),
            (self.tr("Control Character"), "cntrl"),
        )

    def __populateCharTypeCombo(self, combo, isSingle):
        """
        Private method to populate a given character type selection combo box.

        @param combo reference to the combo box to be populated
        @type QComboBox
        @param isSingle flag indicating a singles combo
        @type bool
        """
        for txt, value in self.comboItems:
            combo.addItem(txt, value)
        if isSingle:
            for txt, value in self.singleComboItems:
                combo.addItem(txt, value)

    def __addSinglesLine(self):
        """
        Private slot to add a line of entry widgets for single characters.
        """
        hbox = QWidget(self.singlesItemsBox)
        hboxLayout = QHBoxLayout(hbox)
        hboxLayout.setContentsMargins(0, 0, 0, 0)
        hboxLayout.setSpacing(6)
        hbox.setLayout(hboxLayout)
        cb1 = QComboBox(hbox)
        cb1.setEditable(False)
        self.__populateCharTypeCombo(cb1, True)
        hboxLayout.addWidget(cb1)
        le1 = QLineEdit(hbox)
        le1.setValidator(self.charValidator)
        hboxLayout.addWidget(le1)
        cb1a = QComboBox(hbox)
        cb1a.setEditable(False)
        cb1a.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
        hboxLayout.addWidget(cb1a)
        cb1a.hide()
        cb2 = QComboBox(hbox)
        cb2.setEditable(False)
        self.__populateCharTypeCombo(cb2, True)
        hboxLayout.addWidget(cb2)
        le2 = QLineEdit(hbox)
        le2.setValidator(self.charValidator)
        hboxLayout.addWidget(le2)
        cb2a = QComboBox(hbox)
        cb2a.setEditable(False)
        cb2a.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
        hboxLayout.addWidget(cb2a)
        cb2a.hide()
        self.singlesItemsBoxLayout.addWidget(hbox)

        cb1.activated[int].connect(lambda i: self.__singlesCharTypeSelected(i, cb1))
        cb2.activated[int].connect(lambda i: self.__singlesCharTypeSelected(i, cb2))
        hbox.show()

        self.singlesItemsBox.adjustSize()

        self.singlesEntries.append([cb1, le1, cb1a])
        self.singlesEntries.append([cb2, le2, cb2a])

    def __addRangesLine(self):
        """
        Private slot to add a line of entry widgets for character ranges.
        """
        hbox = QWidget(self.rangesItemsBox)
        hboxLayout = QHBoxLayout(hbox)
        hboxLayout.setContentsMargins(0, 0, 0, 0)
        hboxLayout.setSpacing(6)
        hbox.setLayout(hboxLayout)
        cb1 = QComboBox(hbox)
        cb1.setEditable(False)
        self.__populateCharTypeCombo(cb1, False)
        hboxLayout.addWidget(cb1)
        l1 = QLabel(self.tr("Between:"), hbox)
        hboxLayout.addWidget(l1)
        le1 = QLineEdit(hbox)
        le1.setValidator(self.charValidator)
        hboxLayout.addWidget(le1)
        l2 = QLabel(self.tr("And:"), hbox)
        hboxLayout.addWidget(l2)
        le2 = QLineEdit(hbox)
        le2.setValidator(self.charValidator)
        hboxLayout.addWidget(le2)
        self.rangesItemsBoxLayout.addWidget(hbox)

        cb1.activated[int].connect(lambda i: self.__rangesCharTypeSelected(i, cb1))

        hbox.show()

        self.rangesItemsBox.adjustSize()

        self.rangesEntries.append([cb1, le1, le2])

    def __populateCharacterCombo(self, combo, formatIdentifier):
        """
        Private method to populate a character selection combo.

        @param combo combo box to be populated
        @type QComboBox
        @param formatIdentifier format identifier (one of "-ccp", "-ccn",
            "-cbp", "-cbn", "-csp", "-csn", "-psp", "-psn")
        @type str
        """
        combo.clear()

        if formatIdentifier in ["-ccp", "-ccn"]:
            items = self.__characterCategories
        elif formatIdentifier in ["-csp", "-csn"]:
            items = self.__specialCharacterCategories
        elif formatIdentifier in ["-cbp", "-cbn"]:
            items = self.__characterBlocks
        elif formatIdentifier in ["-psp", "-psn"]:
            items = self.__posixNamedSets

        comboLen = 0
        for txt, code in items:
            combo.addItem(txt, code)
            comboLen = max(comboLen, len(txt))
        combo.setMinimumContentsLength(comboLen)

    def __performSelectedAction(self, formatIdentifier, lineedit, combo):
        """
        Private method performing some actions depending on the input.

        @param formatIdentifier format of the selected entry
        @type str
        @param lineedit line edit widget to act on
        @type QLineEdit
        @param combo combo box widget to act on
        @type QComboBox
        """
        if formatIdentifier == "-i":
            return

        if formatIdentifier in ["-c", "-h", "-o"]:
            lineedit.show()
            lineedit.setEnabled(True)
            if combo is not None:
                combo.hide()
            if formatIdentifier == "-c":
                lineedit.setValidator(self.charValidator)
            elif formatIdentifier == "-h":
                lineedit.setValidator(self.hexValidator)
            elif formatIdentifier == "-o":
                lineedit.setValidator(self.octValidator)
        elif formatIdentifier in [
            "-ccp",
            "-ccn",
            "-cbp",
            "-cbn",
            "-csp",
            "-csn",
            "-psp",
            "-psn",
        ]:
            lineedit.setEnabled(False)
            lineedit.hide()
            if combo is not None:
                combo.show()
            self.__populateCharacterCombo(combo, formatIdentifier)
        else:
            lineedit.setEnabled(False)
            lineedit.hide()
            if combo is not None:
                combo.hide()
        lineedit.clear()

    def __singlesCharTypeSelected(self, index, combo):
        """
        Private slot to handle the activated(int) signal of the single chars
        combo boxes.

        @param index selected list index
        @type int
        @param combo reference to the combo box
        @type QComboBox
        """
        for entriesList in self.singlesEntries:
            if combo == entriesList[0]:
                formatIdentifier = combo.itemData(index)
                self.__performSelectedAction(
                    formatIdentifier, entriesList[1], entriesList[2]
                )
                break

    def __rangesCharTypeSelected(self, index, combo):
        """
        Private slot to handle the activated(int) signal of the char ranges
        combo boxes.

        @param index selected list index
        @type int
        @param combo reference to the combo box
        @type QComboBox
        """
        for entriesList in self.rangesEntries:
            if combo == entriesList[0]:
                formatIdentifier = combo.itemData(index)
                self.__performSelectedAction(formatIdentifier, entriesList[1], None)
                self.__performSelectedAction(formatIdentifier, entriesList[2], None)
                break

    def __formatCharacter(self, char, formatIdentifier):
        """
        Private method to format the characters entered into the dialog.

        @param char character string entered into the dialog
        @type str
        @param formatIdentifier string giving a special format (-c, -h, -i or
            -o) or the already formatted character
        @type str
        @return formatted character string
        @rtype str
        """
        if formatIdentifier == "-c":
            return char
        elif formatIdentifier == "-i":
            return ""

        if formatIdentifier == "-h":
            while len(char) < 2:
                char = "0" + char
            if len(char) > 2:
                return "\\x{{{0}}}".format(char.lower())
            else:
                return "\\x{0}".format(char.lower())
        elif formatIdentifier == "-o":
            while len(char) < 3:
                char = "0" + char
            if len(char) > 3:
                char = char[:3]
            return "\\{0}".format(char)
        elif formatIdentifier in ["-ccp", "-cbp", "-csp"]:
            return "\\p{{{0}}}".format(char)
        elif formatIdentifier in ["-ccn", "-cbn", "-csn"]:
            return "\\P{{{0}}}".format(char)
        elif formatIdentifier == "-psp":
            return "[:{0}:]".format(char)
        elif formatIdentifier == "-psn":
            return "[:^{0}:]".format(char)
        else:
            return formatIdentifier

    def getCharacters(self):
        """
        Public method to return the character string assembled via the dialog.

        @return formatted string for character classes
        @rtype str
        """
        regexp = ""

        # negative character range
        if self.negativeCheckBox.isChecked():
            regexp += "^"

        # predefined character ranges
        if self.wordCharCheckBox.isChecked():
            regexp += "\\w"
        if self.nonWordCharCheckBox.isChecked():
            regexp += "\\W"
        if self.digitsCheckBox.isChecked():
            regexp += "\\d"
        if self.nonDigitsCheckBox.isChecked():
            regexp += "\\D"
        if self.newlineCheckBox.isChecked():
            regexp += "\\R"
        if self.nonNewlineCheckBox.isChecked():
            regexp += "\\N"
        if self.whitespaceCheckBox.isChecked():
            regexp += "\\s"
        if self.nonWhitespaceCheckBox.isChecked():
            regexp += "\\S"
        if self.horizontalWhitespaceCheckBox.isChecked():
            regexp += "\\h"
        if self.nonHorizontalWhitespaceCheckBox.isChecked():
            regexp += "\\H"
        if self.verticalWhitespaceCheckBox.isChecked():
            regexp += "\\v"
        if self.nonVerticalWhitespaceCheckBox.isChecked():
            regexp += "\\V"

        # single characters
        for entrieslist in self.singlesEntries:
            formatIdentifier = entrieslist[0].itemData(entrieslist[0].currentIndex())
            char = (
                entrieslist[2].itemData(entrieslist[2].currentIndex())
                if formatIdentifier
                in ["-ccp", "-ccn", "-cbp", "-cbn", "-csp", "-csn", "-psp", "-psn"]
                else entrieslist[1].text()
            )
            regexp += self.__formatCharacter(char, formatIdentifier)

        # character ranges
        for entrieslist in self.rangesEntries:
            if not entrieslist[1].text() or not entrieslist[2].text():
                continue
            formatIdentifier = entrieslist[0].itemData(entrieslist[0].currentIndex())
            char1 = entrieslist[1].text()
            char2 = entrieslist[2].text()
            regexp += "{0}-{1}".format(
                self.__formatCharacter(char1, formatIdentifier),
                self.__formatCharacter(char2, formatIdentifier),
            )

        if regexp:
            if (
                regexp.startswith("\\")
                and regexp.count("\\") == 1
                and "-" not in regexp
            ) or len(regexp) == 1:
                return regexp
            else:
                return "[{0}]".format(regexp)
        else:
            return ""
